
#include "config.h"

#include "constants.h"

#include <fstream>
#include <map>
#include <sstream>


using namespace std;


// Reads an integer from the beginning of the given string.
bool uintFromString( const string & s, int & result )
{
    istringstream iss( s );
    unsigned int i;
    if ( !(iss >> i) )
        return false;

    result = i;
    return true;
}


// Break a string into tokens using whitespace.
vector<string> tokenize( const string & input )
{
    const char ws[] = " \t\n\r";
    vector<string> tokens;
    int startOfWs = -1;
    int startOfWord = input.find_first_not_of( ws );
    while ( startOfWord != string::npos )
    {
        startOfWs = input.find_first_of( ws, startOfWord );
        if ( startOfWs == string::npos )
            startOfWs = input.size();

        tokens.push_back( input.substr( startOfWord, startOfWs - startOfWord ) );

        startOfWord = input.find_first_not_of( ws, startOfWs );
    }

    return tokens;
}


Config * Config::instance = 0;


Config * Config::self()
{
    if ( !instance )
        instance = new Config();

    return instance;
}


Config::Config()
  : m_maxThreads( defaultMaxThreads ),
    m_threadIncrement( defaultThreadIncrement ),
    m_bbPort( defaultBbPort ),
    m_replicaPort( defaultReplicaPort ),
    m_peers(),
    m_useSyslog( false ),
    m_logFile( defaultLogFile )
{
}


int Config::read( const std::string & file )
{
    std::ifstream ifs( file.c_str() );
    std::string line;

    while ( ifs && std::getline( ifs, line ) )
    {
        vector<string> tokens = tokenize( line );

        if ( tokens.size() < 2 )
            continue;

        if ( tokens.front() == "THMAX" && tokens.size() == 2 )
            uintFromString( tokens[1], m_maxThreads );
        else if ( tokens.front() == "THINCR" && tokens.size() == 2 )
            uintFromString( tokens[1], m_threadIncrement );
        else if ( tokens.front() == "BBPORT" && tokens.size() == 2 )
            uintFromString( tokens[1], m_bbPort );
        else if ( tokens.front() == "RPORT" && tokens.size() == 2 )
            uintFromString( tokens[1], m_replicaPort );
        else if ( tokens.front() == "PEERS" )
        {
            m_peers.clear();
            for ( int i = 1; i < tokens.size(); ++i )
                m_peers.push_back( tokens[i] );
        }
        else if ( tokens.front() == "USESYSLOG" && tokens.size() == 2 )
        {
            int value = m_useSyslog;
            if ( uintFromString( tokens[1], value ) )
                m_useSyslog = value;
        }
        else if ( tokens.front() == "LOG" && tokens.size() == 2 )
        {
            m_logFile = tokens[1];
        }
    }

    return !ifs.eof();
}


int Config::maxThreads() const
{
    return m_maxThreads;
}


int Config::threadIncrement() const
{
    return m_threadIncrement;
}


int Config::bbPort() const
{
    return m_bbPort;
}


int Config::replicaPort() const
{
    return m_replicaPort;
}


vector<string> Config::peers() const
{
    return m_peers;
}


bool Config::useSyslog() const
{
    return m_useSyslog;
}


string Config::logFile() const
{
    return m_logFile;
}


